package security.Authentication.Test;

import static org.junit.Assert.*;

import java.net.InetAddress;
import java.net.UnknownHostException;

import security.Authentication.Base.AuthenticationChain;
import security.Authentication.Base.AuthenticationHandler;
import security.Authentication.Base.IdentifiedUser;
import security.Authentication.Base.UnknownUser;
import security.Authentication.Encrypted.EncryptedHandler;
import security.Authentication.Encrypted.EncryptedRequest;
import security.Authentication.Guest.GuestHandler;
import security.Authentication.Guest.GuestRequest;
import security.Authentication.Unknown.UnknownRequest;
import security.Authentication.UserPass.UserPassHandler;
import security.Authentication.UserPass.UserPassRequest;

import org.junit.Test;

/**
 * Test cases for the authentication component
 * @author Andreas Carmvall
 */
public class AuthenticationTest {

	/**
	 * Test the chain of responsibility
	 * @throws UnknownHostException 
	 */
	@Test
	public void testChain() throws UnknownHostException {
		InetAddress localHost = InetAddress.getLocalHost();
		AuthenticationChain chain = new AuthenticationChain();
		UnknownRequest unknownRequest = new UnknownRequest(localHost);
		GuestRequest guestRequest = new GuestRequest(localHost);
		UserPassRequest userPassRequest =
				new UserPassRequest(localHost, "TestUser", "Abc123!");
		EncryptedRequest encryptedRequest =
				new EncryptedRequest(localHost, "TestUser", "Abc123!");
		
		// Test a chain with authentication handler
		chain.setNext(new GuestHandler());
		chain.setNext(new UserPassHandler());
		chain.setNext(new EncryptedHandler());
		
		assertTrue(chain.handleRequest(unknownRequest) instanceof UnknownUser);
		assertTrue(chain.handleRequest(guestRequest) instanceof IdentifiedUser);
		assertTrue(chain.handleRequest(userPassRequest) instanceof IdentifiedUser);
		assertTrue(chain.handleRequest(encryptedRequest) instanceof IdentifiedUser);
		
		// Test an empty chain
		chain.clear();
		
		assertTrue(chain.handleRequest(unknownRequest) instanceof UnknownUser);
		assertFalse(chain.handleRequest(guestRequest) instanceof IdentifiedUser);
		assertFalse(chain.handleRequest(userPassRequest) instanceof IdentifiedUser);
		assertFalse(chain.handleRequest(encryptedRequest) instanceof IdentifiedUser);
	}

	/**
	 * Test that a guest handler handles the correct request and return
	 * the correct user
	 * @throws UnknownHostException 
	 */
	@Test
	public void testGuestHandler() throws UnknownHostException {
		InetAddress localHost = InetAddress.getLocalHost();
		AuthenticationHandler handler = new GuestHandler();
		UnknownRequest unknownRequest = new UnknownRequest(localHost);
		GuestRequest guestRequest = new GuestRequest(localHost);

		assertTrue(handler.handleRequest(unknownRequest) instanceof UnknownUser);
		assertTrue(handler.handleRequest(guestRequest) instanceof IdentifiedUser);
	}

	/**
	 * Test that a user pass handler handles the correct request and return
	 * the correct user
	 * @throws UnknownHostException 
	 */
	@Test
	public void testUserPassHandler() throws UnknownHostException {
		InetAddress localHost = InetAddress.getLocalHost();
		AuthenticationHandler handler = new UserPassHandler();
		UnknownRequest unknownRequest = new UnknownRequest(localHost);
		UserPassRequest correctRequest =
				new UserPassRequest(localHost, "TestUser", "Abc123!");
		UserPassRequest wrongRequest =
				new UserPassRequest(localHost, "TestUser", "WrongPass");

		assertTrue(handler.handleRequest(unknownRequest) instanceof UnknownUser);
		assertTrue(handler.handleRequest(wrongRequest) instanceof UnknownUser);
		assertTrue(handler.handleRequest(correctRequest) instanceof IdentifiedUser);
	}

	/**
	 * Test that a encrypted handler handles the correct request and return
	 * the correct user
	 * @throws UnknownHostException 
	 */
	@Test
	public void testEncryptedHandler() throws UnknownHostException {
		InetAddress localHost = InetAddress.getLocalHost();
		AuthenticationHandler handler = new EncryptedHandler();
		UnknownRequest unknownRequest = new UnknownRequest(localHost);
		EncryptedRequest correctRequest =
				new EncryptedRequest(localHost, "TestUser", "Abc123!");
		EncryptedRequest wrongRequest =
				new EncryptedRequest(localHost, "TestUser", "WrongPass");

		assertTrue(handler.handleRequest(unknownRequest) instanceof UnknownUser);
		assertTrue(handler.handleRequest(wrongRequest) instanceof UnknownUser);
		assertTrue(handler.handleRequest(correctRequest) instanceof IdentifiedUser);
	}

}
